﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMeterParamFrame
{
    internal class MeterCommProtocol
    {
        /// <summary>
        /// 操作者代码
        /// </summary>
        private const string CONST_USERCODE = "12345678";
        /// <summary>
        /// 写密码等级02级
        /// </summary>
        private const string CONST_METERLEVEL02 = "02";
        /// <summary>
        /// 写密码等级99级，用于一类参数设置
        /// </summary>
        private const string CONST_METERLEVEL99 = "99";

        /// <summary>
        /// 写密码等级98级，用于智能电能表远程控制部分
        /// </summary>
        private const string CONST_METERLEVEL98 = "98";
        /// <summary>
        /// 写表密码
        /// </summary>
        private const string CONST_METERPWD = "000000";

        #region ---------------读表地址---------------
        /// <summary>
        /// 读表地址
        /// </summary>
        /// <param name="BwCode"></param>
        /// <returns></returns>
        public static byte[] WeaveDataByGetMeterAddr(out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007();

            return DLT.WeaveDataFrame("13", "", "", false, false, false, out BwCode);
        }

        /// <summary>
        /// 读表地址解析
        /// </summary>
        /// <param name="ExplainBytes"></param>
        /// <param name="MeterAddr"></param>
        /// <param name="BwCode"></param>
        /// <param name="ErrString"></param>
        /// <returns></returns>
        public static bool ExplainDataByGetMeterAddr(byte[] ExplainBytes, out string MeterAddr, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, false, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            MeterAddr = "".PadLeft(12,'A');

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            MeterAddr = Item.MeterAdr;

            return true;

        }
        #endregion 

        #region ----------------读表号------------

        /// <summary>
        /// 读表号(非通信地址)
        /// </summary>
        /// <param name="BwCode">返回报文字符串</param>
        /// <returns></returns>
        public static byte[] WeaveDataByGetMeterNo(string MeterAddr, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr);

            return DLT.WeaveDataFrame("11", "04000402", "", false, false, false, out BwCode);
        }

        /// <summary>
        ///  解析报文，返回表号，非通信地址 
        /// </summary>
        /// <param name="ExplainBytes">需要解析的报文</param>
        /// <param name="MeterAddr">返回的表号（不是通信地址）</param>
        /// <param name="BwCode">返回的报文字符串</param>
        /// <returns></returns>
        public static bool ExpalinDataByGetMeterNo(byte[] ExplainBytes, ref string MeterNo, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, false, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            MeterNo = Item.ReturnData.Substring(0, 12);

            return true;
        }

        #endregion

        #region --------------（身份认证）-------------------
        /// <summary>
        /// 组帧（身份认证，获取随机数2和ESAM序列号）
        /// </summary>
        /// <param name="MeterAddr">表通信地址</param>
        /// <param name="MeterID">表号</param>
        /// <param name="Rand">加密机返回的随机数1（8个字节）</param>
        /// <param name="Endata">密文（8个字节）</param>
        /// <param name="BwCode">返回的报文</param>
        /// <returns></returns>
        public static Byte[] WeaveDataByIdentity(string MeterAddr, string MeterID, string Rand, string Endata, out string BwCode)
        {
            string Yz = MeterID.PadLeft(16, '0');  //分散因子

            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, CONST_METERLEVEL02, CONST_METERPWD);

            return DLT.WeaveDataFrame("03", "070000FF", string.Format("{0}|{1}|{2}", Endata, Rand, Yz), true, false, true, out BwCode);
        }

        /// <summary>
        /// 拆帧（身份认证，获取随机数2和ESAM序列号）
        /// </summary>
        /// <param name="ExplainBytes">需要解析的帧</param>
        /// <param name="OutMeterRand">输出随机数2</param>
        /// <param name="ESAMSerial">输入ESAM序列号</param>
        /// <param name="BwCode">转化成字符串的报文</param>
        /// <param name="ErrString">错误描述</param>
        /// <returns></returns>
        public static bool ExplainDataByIdentity(byte[] ExplainBytes, ref string OutMeterRand, ref string ESAMSerial, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, true, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                OutMeterRand = "";
                ESAMSerial = "";
                return false;
            }

            ESAMSerial = Item.ReturnData.Substring(0, 16);      //序列号8个字节，16个字符

            OutMeterRand = Item.ReturnData.Substring(16, 8);    //电表随机数4个字节,8个字符

            return true;

        }

        #endregion

        #region -----------------密钥信息清理--------------------
        /// <summary>
        /// 组帧（密钥信息清理）
        /// </summary>
        /// <param name="KeyData">密钥密文信息</param>
        /// <param name="Mac">MAC</param>
        /// <param name="BwCode">返回报文字符串</param>
        /// <returns></returns>
        public static byte[] WeaveDataByClearKey(string MeterAddr, string KeyData, string Mac, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, CONST_METERLEVEL02, CONST_METERPWD);

            return DLT.WeaveDataFrame("03", "070201FF", string.Format("{0}|00000000|{1}", Mac, KeyData), true, false, true, out BwCode);
        }

        /// <summary>
        /// 拆帧（密钥信息清理）
        /// </summary>
        /// <param name="ExplainBytes"></param>
        /// <param name="BwCode"></param>
        /// <param name="ErrString"></param>
        /// <returns></returns>
        public static bool ExplainDataByClearKey(byte[] ExplainBytes, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, true, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            if ("070201FF" != Item.ReturnData.ToUpper())
            {
                ErrString = "返回数据不一致";
                return false;
            }

            return true;
        }

        #endregion

        #region -------------智能表状态查询------------

        /// <summary>
        /// 组帧（智能表状态查询）
        /// </summary>
        /// <param name="MeterAddr">表通信地址</param>
        /// <param name="BwCode">输出报文</param>
        /// <returns></returns>
        public static byte[] WeaveDataByState(string MeterAddr, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, CONST_METERLEVEL02, CONST_METERPWD);

            return DLT.WeaveDataFrame("03", "078102FF", "", true, false, false, out BwCode);
        }
        /// <summary>
        /// 拆帧（智能表状态查询）
        /// </summary>
        /// <param name="ExplainBytes">字节数组</param>
        /// <param name="StateCode">状态值</param>
        /// <param name="BwCode">报文</param>
        /// <param name="ErrString">错误信息</param>
        /// <returns></returns>
        public static bool ExplainDataByState(byte[] ExplainBytes, ref string StateCode, out string BwCode, out string ErrString)
        {

            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, true, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            StateCode = Item.ReturnData.Substring(0, 8);        //密钥信息

            return true;
        }

        #endregion

        #region ------------密钥下载------------------
        /// <summary>
        /// 密钥下装报文
        /// </summary>
        /// <param name="MeterAddr">表通信地址</param>
        /// <param name="KeyNo">下装密钥类型</param>
        /// <param name="KeyInfo">密钥信息</param>
        /// <param name="Mac">MAC</param>
        /// <param name="KeyData">密钥数据</param>
        /// <param name="BwCode">返回报文</param>
        /// <returns></returns>
        public static Byte[] WeaveDataByUpdateKey(EnumKeyNo KeyNo, string MeterAddr, string KeyInfo, string Mac, string KeyData, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, CONST_METERLEVEL02, CONST_METERPWD);

            switch (KeyNo)
            {
                case EnumKeyNo.参数更新密钥:
                    return DLT.WeaveDataFrame("03", "070202FF", string.Format("{0}{1}|{2}", KeyInfo, Mac, KeyData), true, false, true, out BwCode);

                case EnumKeyNo.身份认证密钥:
                    return DLT.WeaveDataFrame("03", "070203FF", string.Format("{0}{1}|{2}", KeyInfo, Mac, KeyData), true, false, true, out BwCode);

                case EnumKeyNo.主控密钥:
                    return DLT.WeaveDataFrame("03", "070204FF", string.Format("{0}{1}|{2}", KeyInfo, Mac, KeyData), true, false, true, out BwCode);
                default:
                    return DLT.WeaveDataFrame("03", "070201FF", string.Format("{0}{1}|{2}", KeyInfo, Mac, KeyData), true, false, true, out BwCode);
            }

        }

        /// <summary>
        /// 解析密钥下装报文
        /// </summary>
        /// <param name="KeyNo">下装密钥类型</param>
        /// <param name="ExpalinBytes">报文字节数组</param>
        /// <param name="BwCode">报文字符串</param>
        /// <param name="ErrString">错误信息</param>
        /// <returns></returns>
        public static bool ExplainDataByUpdateKey(EnumKeyNo KeyNo, byte[] ExplainBytes, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, true, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            string BsCode = "";

            switch (KeyNo)
            {
                case EnumKeyNo.远程控制密钥:
                    BsCode = "070201FF";
                    break;
                case EnumKeyNo.参数更新密钥:
                    BsCode = "070202FF";
                    break;
                case EnumKeyNo.身份认证密钥:
                    BsCode = "070203FF";
                    break;
                case EnumKeyNo.主控密钥:
                    BsCode = "070204FF";
                    break;
            }

            if (BsCode != Item.ReturnData.ToUpper())
            {
                ErrString = "返回数据不一致";
                return false;
            }

            return true;

        }

        #endregion

        #region ---------------费控功能检测---------------

        /// <summary>
        /// 功能控制
        /// </summary>
        /// <param name="MeterAddr">表通信地址</param>
        /// <param name="KeyData">密文数据</param>
        /// <param name="BwCode">返回报文</param>
        /// <returns></returns>
        public static Byte[] WeaveDataByUserControl(string MeterAddr, string KeyData, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, CONST_METERLEVEL98, CONST_METERPWD);

            return DLT.WeaveDataFrame("1C", "", KeyData, true, true, false, out BwCode);

        }

        /// <summary>
        /// 解析功能控制报文
        /// </summary>
        /// <param name="ExpalinBytes">报文字节数组</param>
        /// <param name="BwCode">报文字符串</param>
        /// <param name="ErrString">错误信息</param>
        /// <returns></returns>
        public static bool ExplainDataByUserControl(byte[] ExplainBytes, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            DLT6452007.ExplainDataFrame(ExplainBytes, false, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            return true;

        }


        #endregion

        #region -----------------一、二类参数设置-------------------
        /// <summary>
        /// 一、二类参数组包
        /// </summary>
        /// <param name="MeterAddr">表通信地址</param>
        /// <param name="IsOneClass">是不是一类参数</param>
        /// <param name="KeyData">加密后的密文</param>
        /// <param name="Mac">MAC校验</param>
        /// <param name="ErrString">错误信息返回</param>
        /// <returns></returns>
        public static byte[] WeaveDataByParameterUpdate(string MeterAddr, bool IsOneClass, string BsCode, string KeyData, string Mac, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, IsOneClass ? CONST_METERLEVEL99 : CONST_METERLEVEL98, CONST_METERPWD);

            return DLT.WeaveDataFrame("14", BsCode, string.Format("{0}|{1}", KeyData, Mac), true, true, true, out BwCode);

        }

        /// <summary>
        /// 解析一、二类参数设置控制报文
        /// </summary>
        /// <param name="ExpalinBytes">报文字节数组</param>
        /// <param name="BwCode">报文字符串</param>
        /// <param name="ErrString">错误信息</param>
        /// <returns></returns>
        public static bool ExplainDataByParameterElseUpdate(byte[] ExplainBytes, out string BwCode, out string ErrString)
        {
            return ExplainDataByUserControl(ExplainBytes, out BwCode, out ErrString);
        }

        #endregion 


        #region -----------------基本参数设置----------------------
        /// <summary>
        /// 基本参数设置打包
        /// </summary>
        /// <param name="MeterAddr">表地址</param>
        /// <param name="Pwd">密码</param>
        /// <param name="Level">等级</param>
        /// <param name="BsCode">标示符</param>
        /// <param name="ParamValue">写入的数据</param>
        /// <param name="BwCode">返回的报文</param>
        /// <returns></returns>
        public static byte[] WeaveDataByStandardUpdate(string MeterAddr, string Pwd, string Level, string BsCode, string ParamValue, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr, CONST_USERCODE, Level, Pwd);

            return DLT.WeaveDataFrame("14", BsCode, ParamValue, true, true, ParamValue.IndexOf('|', 0) < 0 ? false : true, out BwCode);

        }

        /// <summary>
        /// 解析电能表基本参数设置返回帧
        /// </summary>
        /// <param name="ExplainBytes">返回的数据帧</param>
        /// <param name="BwCode">返回数据转为字符串报文</param>
        /// <param name="ErrString">错误描述</param>
        /// <returns></returns>
        public static bool ExplainDataByStandardUpdate(byte[] ExplainBytes, out string BwCode, out string ErrString)
        {
            return ExplainDataByUserControl(ExplainBytes, out BwCode, out ErrString);
        }

        #endregion 


        #region -------------------参数读取------------------

        /// <summary>
        /// 读表参数
        /// </summary>
        /// <param name="BwCode">返回报文字符串</param>
        /// <returns></returns>
        public static byte[] WeaveDataByGetMeterParam(string MeterAddr,string BsCode, out string BwCode)
        {
            DLT6452007 DLT = new DLT6452007(MeterAddr);

            return DLT.WeaveDataFrame("11", BsCode, "", false, false, false, out BwCode);
        }

        /// <summary>
        ///  解析报文，返回表参数 
        /// </summary>
        /// <param name="ExplainBytes">需要解析的报文</param>
        /// <param name="MeterAddr">返回的表号（不是通信地址）</param>
        /// <param name="BwCode">返回的报文字符串</param>
        /// <returns></returns>
        public static bool ExpalinDataByGetMeterParam(byte[] ExplainBytes, out string ReturnParam, out string BwCode, out string ErrString)
        {
            Struct.StExplain Item;

            ReturnParam="";

            DLT6452007.ExplainDataFrame(ExplainBytes, false, out Item);

            BwCode = Item.BwCode;

            ErrString = "";

            if (Item.BlnErr)
            {
                ErrString = string.Format("错误号:{0},错误解释:{1}", Item.ErrNum, Item.ErrDisString);
                return false;
            }

            ReturnParam=Item.ReturnData;

            return true;
        }

        #endregion

    }
}
